<?php
// This file is part of Moodle - http://moodle.org/
//
// Moodle is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// Moodle is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with Moodle.  If not, see <http://www.gnu.org/licenses/>.

defined('MOODLE_INTERNAL') || die();

require_once($CFG->dirroot . '/local/references/convert/refxml.php');
require_once($CFG->dirroot . '/local/references/linking.php');

/**
 * Asset request class that builds references for Structured Content document
 *
 * Included here to separate it out from the rest of SC although it is not
 * a perfect division; reference processing code remains in SC XSL, PHP,
 * and JavaScript.
 *
 * Compared to other asset requests this is super-complicated because it is
 * necessary to send a Refworks request for every reference in the document at
 * once, so we can't just treat them individually like other requests.
 *
 * I have the strong feeling that this class does not work properly and will
 * perform poorly. I think it makes one RefWorks request per reference and it's
 * probably supposed to make one per reference file (or one overall). But this
 * is just a feeling - the references code is hard to understand and to be
 * honest, I don't want to.
 *
 * @package local
 * @subpackage references
 * @copyright 2012 The Open University
 * @license http://www.gnu.org/copyleft/gpl.html GNU GPL v3 or later
 */
class oucontent_asset_request_references extends oucontent_asset_request {
    private $referencesourcesxml, $reflist;

    public function __construct(DOMDocument $document) {
        // Need to pass an element to the parent constructor, but we don't really
        // have one because this is handling the whole document in one request
        parent::__construct($document->documentElement);
        global $CFG;

        // Find list of references from document
        $xpath = new DOMXPath($document);
        $this->referencesourcesxml = $xpath->query('//Reference[@ReferenceID!=""]');

        // Populate a references list array
        $this->reflist = array();
        $tempcounter = 0;
        foreach ($this->referencesourcesxml as $reference) {
            $composite = array();
            // For each reference create a source (src) attribute
            $refsrc = $reference->getAttribute('src');

            // create a reference list attribute array
            $composite['element'] = $reference;
            $composite['refid'] = $reference->getAttribute('ReferenceID');
            $composite['style'] = $reference->getAttribute('ReferenceStyle');
            $composite['refsrc'] = $refsrc;
            // reset the style attribute with urlencoding
            // TODO This is WRONG. All modified attributes here must use the
            // x_ prefix to distinguish them from the input document.
            $reference->setAttribute("ReferenceStyle", urlencode($composite['style']));
            if ($child = $reference->firstChild) {
                $composite['title'] = oucontent_get_xml_element_text($child);
            }
            // TODO This code creates an entirely useless array which only ever
            // has one element. I suspect there is some vague intention here
            // that it should only create one top-level entry for each
            // different file, but it doesn't work that way at all.
            $this->reflist[$tempcounter][] = $composite;
            $tempcounter++;
        }

        // Loop through the references list attribute array, adding each one to
        // request the file
        foreach ($this->reflist as $val => $val2) {
            foreach ($val2 as $idelement) {
                // This loop does nothing except set $idelement
                $codecheckerdisallowsemptyloops = true;
            }
            $this->add_file($idelement['refsrc'], false, $val);
        }
    }

    protected function got_files($oucontent, DOMElement $element, $files) {
        // Begin creation of references.xml file
        $newdom = new DOMDocument('1.0', 'utf-8');
        $root = $newdom->createElement('references');
        $root = $newdom->appendChild($root);
        $refxml = new refxml();

        $fs = get_file_storage();

        foreach ($this->reflist as $val => $val2) {
            foreach ($val2 as $idelement) {
                // This loop does nothing except set $idelement and store
                // the refid as entry 0 in idarray.
                $idarray[0] = $idelement['refid'];
            }
            // Find matching file using key
            $file = $files[$val];

            // Make the x_src value
            $idelement['element']->setAttribute('x_src', $file->filename);

            // Fail?
            if (!$file->ok) {
                $idelement['element']->setAttribute('x_notfound', 'y');
                $idelement['element']->setAttribute('x_reason', $file->reason);
                continue;
            } else {
                $this->set_hash_attributes($oucontent, $file, $element);
            }

            // Need the actual file contents
            $filefolderhash = self::get_filefolder_hash($file);
            $fileinfo = oucontent_get_documentfile_info($oucontent, '/' . $filefolderhash . '/',
                    $file->filename);
            $pathnamehash = $fs->get_pathname_hash($fileinfo->contextid, $fileinfo->component ,
                    $fileinfo->filearea, $fileinfo->itemid, $fileinfo->filepath, $fileinfo->filename);
            $sourcefile = $fs->get_file_by_hash($pathnamehash)->get_content();

            $returnedtype = $refxml->test_data_type($sourcefile, 'RIS');
            //if not a RIS file check if RefWorksXML
            if ($returnedtype == false) {
                $returnedtype = $refxml->test_data_type($sourcefile, 'RefWorksXML');
            }

            if ($returnedtype == false) {
                throw new moodle_exception('errorsystem', 'oucontent', '',
                        'Problem with ' . $reffilename);
            }

            $fileformat = $refxml->return_data_type($sourcefile);
            if ($fileformat == false) {
                throw new moodle_exception('errorsystem', 'oucontent', '',
                        'Failed to return data type');
            }
            $data = $refxml->return_transform_in($sourcefile, $fileformat);
            if ($data == false) {
                throw new moodle_exception('errorsystem', 'oucontent', '',
                        "Failed to transform $sourcefile using refxml->return_transform_in()");
            }
            $referencesreturned = $refxml->return_reference($data, $idarray, false, true);
            if ($referencesreturned == false) {
                throw new moodle_exception('errorsystem', 'oucontent', '',
                        'Failed to return_reference');
            }

            $counter = 0;
            foreach ($referencesreturned as $domelement) {
                $domnode = $newdom->importNode($domelement, true);
                $root->appendChild($domnode);
                // create attribute node
                $srcnode = $newdom->createAttribute('src');
                $domnode->appendChild($srcnode);
                // create attribute value node
                $srcvalue = $newdom->createTextNode($file->filename);
                $srcnode->appendChild($srcvalue);
                // create attribute node
                $titlenode = $newdom->createAttribute('title');
                $domnode->appendChild($titlenode);
                // create attribute value node
                $titlevalue = $newdom->createTextNode($val2[$counter]['title']);
                $titlenode->appendChild($titlevalue);
                // create attribute node
                $stylenode = $newdom->createAttribute('style');
                $domnode->appendChild($stylenode);
                // create attribute value node
                $stylevalue = $newdom->createTextNode(urlencode($val2[$counter]['style']));
                $stylenode->appendChild($stylevalue);
                $counter++;
            }
        }
        // create array of reference weblinks
        $linking = linking::create_link($newdom, '%%COURSESHORTNAME%%');

        $referencesxml = $newdom->saveXML();

        //sort creation and placing of ReferenceURL links in xml
        $referenceindex = 0;
        foreach ($this->referencesourcesxml as $individualreference) {
            if (isset($linking[$referenceindex])) {
                $individualreference->setAttribute("ReferenceURL", $linking[$referenceindex]);
            }
            $referenceindex++;
        }

        // If references exist copy the references xml into the relevant target location
        if (count($this->reflist) != 0) {
            // Store References XML file in target location
            oucontent_documentfile_save($oucontent, '/', 'references.xml', $referencesxml);
        }
    }
}
